#pragma once
#include <iostream>
#include <pthread.h>
#include <vector>
#include "Mutex.hpp"
#include "Log.hpp"
#include "Cond.hpp"
#include "Thread.hpp"
#include "Task.hpp"
#include <queue>

// 基于单例模式的线程池
namespace PoolModel
{
    using namespace MutexModel;
    using namespace CondModel;
    using namespace LogModel;
    using namespace ThreadModel;
    const int threadsnum = 5;

    template <class T>
    class ThreadPool
    {
    private:
        void WakeOne()
        {
            _cond.Signal(); // 唤醒一个线程
            Log(LogLevel::INFO) << "唤醒一个休眠线程";
        }
        void WakeAll()
        {
            _cond.Broadcast();
            Log(LogLevel::INFO) << "唤醒全部休眠线程";
        }
        // 线程需执行的函数
        void HandlerTask()
        {
            char name[64];
            pthread_getname_np(pthread_self(), name, sizeof(name)); // 获取线程代号
            while (true)
            {
                T t; // 创建一个任务对象
                {
                    Steward gj(_mutex);
                    // 先判断是否有任务
                    while (_task_t.empty() && _isruning) // 如果没有任务就进入等待
                    {
                        _wait_num++;
                        _cond.Wait(_mutex);
                        _wait_num--;
                    }
                    // 状态为停止并且队列内无任务，直接退出
                    if (!_isruning && _task_t.empty())
                    {
                        Log(LogLevel::DEBUG) << "线程退出";
                        break;
                    }

                    t = _task_t.front();
                    _task_t.pop();
                }
                Log(LogLevel::DEBUG) << name;
                t(); // 处理任务
            }
        }
        ThreadPool(int thread_num = threadsnum)
            : _thread_num(thread_num),
              _isruning(false),
              _wait_num(0)
        {
            Init();
        }
        ~ThreadPool()
        {
                }
        void Init()
        {
            // Log(LogLevel::INFO) << "初步初始化线程池";
            for (int i = 0; i < _thread_num; i++)
            {
                _threads.emplace_back([this]()
                                      { HandlerTask(); });
            }
        }
        // 启动线程池
        void Start()
        {
            if (_isruning)
                return; // 如果已经是启动状态
            _isruning = true;
            for (auto &thread : _threads)
            {
                thread.start();
                Log(LogLevel::DEBUG) << "启动一个新线程" << thread.GetName();
            }
        }

    public:
        ThreadPool(ThreadPool<T> &) = delete;
        ThreadPool<T> &operator=(ThreadPool<T> &) = delete;

        static ThreadPool<T> *GetInstance()
        {
            if (_instance == nullptr)
            {
                // 因为在创建单例时也可能会发生线程安全问题
                Steward gj(_inst_mutex);
                if (_instance == nullptr) // 如果还未被创建，就进行创建，只能被创建一次
                {
                    _instance = new ThreadPool<T>();
                    _instance->Start();
                    Log(LogLevel::DEBUG) << "创建线程池单例";
                    return _instance;
                }
            }
            Log(LogLevel::DEBUG) << "获取线程池单例";
            return _instance;
        }

        void Join()
        {
            for (auto &thread : _threads)
            {
                // 要回收就必须保证进程没有在等待状态，并且任务全部处理完成
                thread.Join();
                Log(LogLevel::INFO) << "join" << thread.GetName();
            }
        }
        // 生成任务
        bool Enqueue(const T &t)
        {
            if (_isruning) // 判断线程池是否在运行
            {
                Steward gj(_mutex); // 保证线程安全，保证在放任务时是原子的
                _task_t.push(t);
                if (_wait_num > 0) // 如果此时线程全部都在等待
                    WakeOne();     // 唤醒一个线程
                return true;
            }
            return false;
        }

        void Stop()
        {
            // if (!_isruning)
            // {
            //     return;
            // }
            Steward gj(_mutex);
            _isruning = false;
            // 线程池还在运行
            WakeAll();
        }

    private:
        int _thread_num;              // 需要创建几个线程
        std::vector<Thread> _threads; // 管理线程

        Cond _cond;
        Mutex _mutex;

        std::queue<T> _task_t; // 用来装任务的

        bool _isruning; // 线程池是否启动
        int _wait_num;  // 进入等待状态的线程

        static ThreadPool<T> *_instance; // 单例
        static Mutex _inst_mutex;
    };
    template <class T>
    ThreadPool<T> *ThreadPool<T>::_instance = nullptr; // 静态成员变量需在外部给初始值
    template <class T>
    Mutex ThreadPool<T>::_inst_mutex;
}